
import GameLogic
import GameKeys
import GameTypes
import PhysicsConstraints
import Rasterizer

import random
import string

debug = 0

GameLogic.globalDict = dict(\

GRAVITY = (0, 0, -150),\
LOGICTICRATE = 40,\
MAXLOGICFRAME = 4,\
MAXPHYSICSFRAME = 4,\
PHYSICSTICRATE = 30,\

DEACTIVATIONANGULARTHRESHOLD = 5.0,\
DEACTIVATIONLINEARTHRESHOLD = 5.0,\
DEACTIVATIONTIME = 0.5,\
LINEARAIRDAMPING = 1.0,\
NUMITERATIONS = 4,\
NUMTIMESUBSTEPS = 4,\

BACKGROUNDCOLOUR = (0.576, 0.6, 0.48, 1.0),\
AMBIENTCOLOUR = (0, 0, 0),\
MISTCOLOUR = (0, 0, 0),\
MISTSTART = 100,\
MISTEND = 25,\
SHOWMOUSE = False,\

ACTIVITYCULLINGRADIUS = 0.5,\

CAMERA_FAR = 100,\
CAMERA_FRUSTUM_CULLING = True,\
CAMERA_LENS = 35,\
CAMERA_NEAR = 1,\
CAMERA_PERSPECTIVE = False,\
CAMERA_ORTHO_SCALING = 70,\

PLAYER_WALK = 350,\
PLAYER_JUMP = 900,\
PLAYER_START_POSITION = [-32, 0, 32],\

GROUND_POSITIONS = [],\
STRAWBERRY_POSITIONS = [],\
LEMONADE_POSITIONS = [],\
SPIKE_POSITIONS = [],\
BRIDGE_POSITIONS = [],\

TIME = 0,\
)

if debug:
	print "Debug enabled"
	print GameLogic.globalDict

gd = GameLogic.globalDict

def getController():
	""" Return current controller.
	
	@rtype: SCA_PythonController
	"""
	return GameLogic.getCurrentController()

def getOwner():
	""" Return current controllers owner object.
	
	@rtype: KX_GameObject
	"""
	return GameLogic.getCurrentController().owner

def getScene():
	""" Return the current scene.
	
	@rtype: KX_Scene
	"""
	return GameLogic.getCurrentScene()

def doGameLogic():
	"""
	"""
	GameLogic.setGravity(gd["GRAVITY"])
	GameLogic.setLogicTicRate(gd["LOGICTICRATE"])
	GameLogic.setMaxLogicFrame(gd["MAXLOGICFRAME"])
	GameLogic.setMaxPhysicsFrame(gd["MAXPHYSICSFRAME"])
	GameLogic.setPhysicsTicRate(gd["PHYSICSTICRATE"])
	
def doPhysicsConstraints():
	"""
	"""
	PhysicsConstraints.setDeactivationAngularTreshold(gd["DEACTIVATIONANGULARTHRESHOLD"]) # Sets the angular velocity that an object must be below before the deactivation timer can start.
	PhysicsConstraints.setDeactivationLinearTreshold(gd["DEACTIVATIONANGULARTHRESHOLD"]) # Sets the linear velocity that an object must be below before the deactivation timer can start.
	PhysicsConstraints.setDeactivationTime(gd["DEACTIVATIONTIME"]) # Sets the amount of time that an object must stay below the velocity thresholds before the object enters sleep mode.
	PhysicsConstraints.setLinearAirDamping(gd["LINEARAIRDAMPING"]) # Sets the linear air resistance for all objects in the scene.
	PhysicsConstraints.setNumIterations(gd["NUMITERATIONS"]) # Sets the number of times an iterative constraint solver is repeated.
	PhysicsConstraints.setNumTimeSubSteps(gd["NUMTIMESUBSTEPS"]) # Sets the number of time sub steps.  (This increases the accuracy of the physics but decreases the game framerate.)

def doRasterizer():
	"""
	"""
	Rasterizer.setBackgroundColor(gd["BACKGROUNDCOLOUR"])
	Rasterizer.setAmbientColor(gd["AMBIENTCOLOUR"])
	for setting in ("lights", "shaders", "shadows", "ramps", "nodes", "extra_textures"):
		Rasterizer.setGLSLMaterialSetting(setting, False)
	Rasterizer.setMaterialMode(Rasterizer.KX_TEXFACE_MATERIAL)
	Rasterizer.showMouse(gd["SHOWMOUSE"])
	Rasterizer.disableMist()
	Rasterizer.disableMotionBlur()

def doScene():
	"""
	"""
	scene = getScene()
	scene.activity_culling_radius = gd["ACTIVITYCULLINGRADIUS"]

def doCamera():
	"""
	"""
	camera = getScene().active_camera
	camera.far = gd["CAMERA_FAR"]
	camera.frustum_culling = gd["CAMERA_FRUSTUM_CULLING"]
	camera.lens = gd["CAMERA_LENS"]
	camera.near = gd["CAMERA_NEAR"]
	camera.perspective = gd["CAMERA_PERSPECTIVE"]

###################
# Generic methods #
###################

def addAnObject(controller, object, time=0, linearvelocity=(0, 0, 0), angularvelocity=(0, 0, 0), actuator="aAddObject"):
	""" Add and return an object.

	@type controller: SCA_PythonController
	@keyword controller: Controller linked to add object actuator.
	@type object: KX_GameObject or string
	@keyword object: Object to add.

	@type time: integer
	@keyword time: Lifetime of object in frames.
	@type linearvelocity: tuple
	@keyword linearvelocity: 3-tuple of floats. (x, y, z)
	@type angularvelocity: tuple
	@keyword angularvelocity: 3-tuple of floats. (x, y, z)
	@type actuator: string
	@keyword actuator: Name of add object actuator.

	@rtype: KX_GameObject
	@return: Returns newly created object.
	"""
	aAddObject = controller.actuators[actuator]
	aAddObject.object = object
	aAddObject.time = time
	aAddObject.linearVelocity = linearvelocity
	aAddObject.angularVelocity = angularvelocity
	aAddObject.instantAddObject()
	return aAddObject.objectLastCreated

def sceneObjectsNamed(name):
	"""
	
	@type name: string
	@keyword name: Name to match with all objects in scene.
		
	@rtype: list
	@return: List of objects matching name.
	"""
	return [object for object in getScene().objects if object.name[2:] == name]

def playSound(name):
	"""
	
	@type name: string
	@keyword name: Name of sound actuator to play.
	"""
	controller = getController()
	aSound = controller.actuators["aSound_" + name]
	controller.activate(aSound)

########
# Game #
########

def doWorld():
	"""
	"""
	doGameLogic()
	doPhysicsConstraints()
	doRasterizer()
	doScene()
	doCamera()
	doCreation()

def doCreation():
	"""
	"""
	playSound("Creation")
	controller = getController()

	addAnObject(controller, "Glass")

	for za in xrange(-16, 24, 8):
		gd["GROUND_POSITIONS"].append([0, 0, za])
		for i in xrange(2):
			gd["STRAWBERRY_POSITIONS"].append([int(random.choice(xrange(-24, 24, 2))), 0, (za + 4)])

	for zb in xrange(-8, 16, 16):
		gd["SPIKE_POSITIONS"].append([int(random.choice(xrange(-24, 24, 2))), 0, (zb + 1)])
		for i in xrange(2):
			gd["LEMONADE_POSITIONS"].append([int(random.choice(xrange(-24, 24, 2))), 0, (zb + 3)])		

	for zc in xrange(-16, 24, 16):
		pc = [int(random.choice(xrange(-24, 24, 2))), 0, (zc + 1)]
		gd["BRIDGE_POSITIONS"].append(pc)
		gd["STRAWBERRY_POSITIONS"].append(pc)

	for p in gd["GROUND_POSITIONS"]:
		addAnObject(controller, "Ground").position = p
	for p in gd["STRAWBERRY_POSITIONS"]:
		addAnObject(controller, "Strawberry").position = p
	for p in gd["SPIKE_POSITIONS"]:
		addAnObject(controller, "Spike").position = p
	for p in gd["BRIDGE_POSITIONS"]:
		addAnObject(controller, "Bridge").position = p

	player = addAnObject(controller, "Player").position = gd["PLAYER_START_POSITION"]

def playerMovement():
	"""
	"""
	sKeyboard = getController().sensors["sKeyboard"]
	if sKeyboard.positive:
		owner = getOwner()
		x = z = 0
		for event in sKeyboard.events:
			if event[1] == 2:
				if event[0] == GameKeys.AKEY:
					playSound("PlayerWalk")
					x = -gd["PLAYER_WALK"]
				if event[0] == GameKeys.DKEY:
					playSound("PlayerWalk")
					x = gd["PLAYER_WALK"]
				if event[0] == GameKeys.WKEY:
					if owner["ON_GROUND"] == True:
						playSound("PlayerJump")
						z = gd["PLAYER_JUMP"]

				if event[0] == GameKeys.ONEKEY:
					gameRestart()

		owner.applyForce((x, 0, z), True)

def gameRestart():
	"""
	"""
	playSound("GameRestart")
	controller = getController()
	aGameRestart = controller.actuators["aGameRestart"]
	controller.activate(aGameRestart)

def onGround():
	""" Returns True if owner object is colliding with GROUND object, False otherwise.
	"""
	sHitGround = getController().sensors["sHitGround"]
	owner = getOwner()
	if sHitGround.positive:
		owner["ON_GROUND"] = True
	else:
		owner["ON_GROUND"] = False

def cleanUp():
	"""
	"""
	for name in ("Player", "Player"):
		objects = sceneObjectsNamed(name)
		if objects:
			for object in objects:
				p = object.position
				x = y = z = 0
				if p[0] < -32:
					x, z = 32, (p[2] + 8)
				if p[0] > 32:
					x, z = -32, (p[2] - 8)
				if p[2] < -32:
					p = gd[name.upper() + "_START_POSITION"]
					x, z = p[0], p[2]
				if x != 0 or z != 0:
					object.position = [x, y, z]

	o = sceneObjectsNamed("Strawberry")
	if o == []:
		for i in xrange(4):
			addAnObject(getController(), "Particles").position = [random.uniform(-16, 16), 0, random.uniform(-32, 32)]

def eatStrawberry():
	"""
	"""
	controller = getController()
	sHitStrawberry = controller.sensors["sHitStrawberry"]
	if sHitStrawberry.positive:
		object = sHitStrawberry.hitObject
		if object:
			playSound("Strawberry")
			doParticle(object.position)
			object.endObject()
			owner = getOwner()
			owner["STRAWBERRY"] = owner["STRAWBERRY"] + 1
			if owner["STRAWBERRY"] >= 4:
				position = gd["LEMONADE_POSITIONS"].pop()
				doParticle(position)
				addAnObject(controller, "Lemonade").position = position
				owner["STRAWBERRY"] = owner["STRAWBERRY"] - 4

def eatLemonade():
	"""
	"""
	controller = getController()
	sHitLemonade = controller.sensors["sHitLemonade"]
	if sHitLemonade.positive:
		object = sHitLemonade.hitObject
		if object:
			playSound("Lemonade")
			doParticle(object.position)
			object.endObject()
			try:
				random.choice(sceneObjectsNamed("Bridge")).endObject()
			except:
				pass
			owner = getOwner()
			owner["LEMONADE"] = owner["LEMONADE"] + 1

def doParticle(position):
	"""
	"""
	playSound("Particle")
	addAnObject(getController(), "Particle").position = position

def flyParticle():
	"""
	"""
	owner = getOwner()
	if owner["TIMER"] > 1:
		owner.endObject()
	owner.applyMovement((0, -2, 0), True)
	s = owner.scaling[0] + 1
	owner.scaling = [s, s, s]

def doFinish():
	"""
	"""
	doParticle([random.uniform(-32, 32), 0, random.uniform(-32, 32)])
	showClock()
	getOwner().endObject()

def showClock():
	"""
	"""
	if gd["TIME"] == 0:
		gd["TIME"] = getScene().objects["OBWorld"]["TIME"]
	controller = getController()
	x = -24
	t = str(gd["TIME"])
	for n in t:
		if n.isdigit():
			object = "Number_" + n
		else:
			object = "Number"
		number = addAnObject(controller, object, 15)
		number.position = [x, -32, 0]
		number.scaling = [8, 8, 8]
		x = x + 4

def onSpike():
	"""
	"""
	controller = getController()
	sHitSpike = controller.sensors["sHitSpike"]
	if sHitSpike.positive:
		playSound("Fail")
		gameRestart()